var Message= function (from,to,body,datetime) {
    this.from     = from ;
    this.to       = to   ;
    this.body     = body ;
    this.datetime = datetime ;  
}

var Chat = function () {
    this.msg          = Array();
    this.chat_status  = 'inactive' ;
    this.last_status  = 'inactive' ; //this my last chat activity
    this.buddy_status = '' ;
    this.show         = 'unavailable' ;
    this.buddy        = null;
};

var Friend = function () {
    this.name         =  null ;
    this.jid          =  null ;
    this.approved     =  false;
    this.subscription =  null ;
    this.group        =  null ;
    this.show         =  'unavailable' ;
    this.status       =  '' ;
    this.activity     =  'inactive' ;
    this.photo        =  null ;
};

var YAJSChat={ 
              jid               :   null,
              debug             :   true,
              password          :   null,
              bosh_service      :   null,
              connection        :   null,
              __jquery          :   null,
              chats             :   {},
              friends           :   {},
              other_resource    :   {},
              __log             :   yajschat_log,
              __connect         :   yajschat_connect,
              __onConnect       :   yajschat_onConnect,
              __getMessage      :   yajschat_getMessage,
              __appendChat      :   yajschat_appendChat,
              __setBuddyStatus  :   yajschat_setBuddyStatus,
              __setChatStatus   :   yajschat_setChatStatus,
              __getChat         :   yajschat_getChat,
              __getRoster       :   yajschat_getRoster,
              __onrosterChanged :   yajschat_onrosterChanged,
              __onPresence      :   yajschat_onPresence,
              init              :   yajschat_init,
              disconnect        :   yajschat_disconnect,
              sendMessage       :   yajschat_sendMessage,
              getFriendsList    :   yajschat_getRoster,
              setChatStatus     :   yajschat_setChatStatus,
              addContact        :   yajschat_addContact,
              approveContact    :   yajschat_approveContact,
              bind              :   yajschat_bind,
              trigger           :   yajschat_trigger,
}
YAJSChat.__jquery = $(YAJSChat);

/*
 * Events :
 *          error
 *          connecting
 *          connfail
 *          authentication
 *          authfail
 *          connected
 *          disconnected
 *          disconnecting
 *          atteched
 *
 *          sendMessage
 *          getMessage
 *          getFriendList
 *          getStatus
 *          chatStatus
 *          buddyStatus
 *          approveBuddy
 *
 *
 *
*/ 
function yajschat_bind(event, data){
   this.__jquery.bind(event,data); 
}

function yajschat_trigger(event,data,elem){
    this.__jquery.trigger(event,data,elem) ;
}


function yajschat_approveContact(contact){
    this.connection.send($pres({to: contact,"type": "subscribed"}));
}

function yajschat_addContact(jid_val,name_val,group_val){
        var iq = $iq({type: "set"}).c("query", {xmlns: "jabber:iq:roster"})
        .c("item", {jid:jid_val, name:name_val, group:group_val });
        
        var subscribe = $pres({to: jid_val , "type": "subscribe"});
        this.connection.send(subscribe);
        
        alert('asdad');

}

function yajschat_onPresence( presence ) {
    var ptype = $(presence).attr('type');
    var from = $(presence).attr('from');
    var to = $(presence).attr('from');



    var from_id = Strophe.getBareJidFromJid(from);
    var to_id   = Strophe.getBareJidFromJid(from);
    if ( from_id == YAJSChat.jid ) { //I don't what is it ! maybe just infrom  about my other resource which got lost
        from_id=from;     
        YAJSChat.other_resource[from]=from;
        return true ; 
    }

    if( ptype == 'subscribe' ){
        console.log("just added : "+ from);
        console.log(presence);
        this.trigger('approveBuddy',[from]);
    }
    if( ptype != 'error' ) {
        if ( ptype == 'unsubscribed' ) ; //TODO: handle unsubscribed things 
        if ( ptype == 'unavailable' ) 
            YAJSChat.__setBuddyStatus(from,'unavailable');
        else {
            var show = $(presence).find("show").text();
            var status = $(presence).find("status").text();
            YAJSChat.__setBuddyStatus(from,show,status);
        }
        
            

    }
    return true;

}


function yajschat_onrosterChanged(iq){
    console.log(iq);
    $(iq).find('item').each(function () {
        var sub    = $(this).attr('subscription');
        var jid    = $(this).attr('jid');
        var name   = $(this).attr('name') || jid;
        var group  = $(this).children('group').text();

        if(sub == 'remove'){
            //contact is being removed (it seems it happend just by my in other resource )
            //YAJSChat.friends[jid] should removed
        }else {
            if(YAJSChat.friends[jid] == null ) //if this friends is not in list so it new once, just add to friends list
                YAJSChat.friends[jid]          = new Friend();
            YAJSChat.friends[jid].jid          = jid;
            YAJSChat.friends[jid].name         = name;
            YAJSChat.friends[jid].group        = group;
            YAJSChat.friends[jid].subscription = sub;
            if($(this).attr('ask'))
                YAJSChat.friends[jid].approved = false;
            else 
                YAJSChat.friends[jid].approved = true;


        }
    });

}
function yajschat_getRoster(iq) {
     
    $(iq).find('item').each(function () {
            var add_f          = new Friend() 
            add_f.jid          = $(this).attr('jid');
            add_f.name         = $(this).attr('name') || add_f.jid;
            add_f.subscription = $(this).attr('subscription') ;
            add_f.group        = $(this).children('group').text();
            if($(this).attr('ask'))
                add_f.approved       = false;
            else 
                add_f.approved       = true;
            YAJSChat.friends[add_f.jid] = add_f ;
    } );

    YAJSChat.trigger('getFriendList',YAJSChat.friends);
    YAJSChat.__log('get friends of jid '+  YAJSChat.jid );

}

function yajschat_getChat(chat_buddy) {
    return this.chats[chat_buddy];
}

function yajschat_appendChat(from,to,body) {
    
    var chat_buddy=from;
    if ( from == this.jid ) {
        chat_buddy = to ; 
    }

    if(this.chats[chat_buddy] == null ) {
        this.chats[chat_buddy]=new Chat();
        this.chats[chat_buddy].buddy=chat_buddy;
    }

    if ( from != this.jid ) {
        //message recived from buddy so she is Available now
        //this.__setBuddyStatus(chat_buddy,'');
    }


    this.chats[chat_buddy].msg.push (  new Message(from ,to ,body, new Date() ) ) ;

   // this.__log(this.chats);
}


function yajschat_setBuddyStatus(jid,show,status){
    if(!status)
        status='';

    chat_buddy = Strophe.getBareJidFromJid(jid);
    //TODO: some times send  new friend status  which add currenty , so she is not in your friends list , we should append new friends to list
    if(this.friends[chat_buddy] != null) {
            this.friends[chat_buddy].status = status ;
            this.friends[chat_buddy].show   = show ;
    }


    if(this.chats[chat_buddy] != null ) {
        this.chats[chat_buddy].buddy_status = status ;
        this.chats[chat_buddy].show         = show ;
    }

    if(this.other_resource[chat_buddy] != null )
        this.other_resource.push(chat_buddy);
    this.trigger('buddyStatus',[chat_buddy,show,status,this.friends]);
    this.__log('status ' + chat_buddy +' changed to "' + show + ' ' + status+'"' ) ; 

}

/*
 *  status are :
 *              * active    : The user is paying attention to the chat
 *              * inactive  : Inactive: The user is not paying attention to the chat.
 *              * composing : The user is typing a message for the chat.
 *              * paused    : The user was typing, but has briefly stopped.
 *              * gone      : The user has closed or left the chat.
 *
*/ 
function yajschat_setChatStatus(chat_buddy,status,other_buddy){

    //if this function call from public method just send my status to other 
    if(!other_buddy)
    {
        if(this.chats[chat_buddy] != null ) {
            //check if we set this status before save BW and does not send it again
            if(this.chats[chat_buddy].last_status == status )
                return true ; 
            this.chats[chat_buddy].last_status  = status ;
        }
            
        if(status =='active' || status =='inactive'  || status == 'composing' ||  status =='paused' || status =='gone' ) {
            var notify = $msg({to: chat_buddy, "type": "chat"}).c(status, {xmlns: "http://jabber.org/protocol/chatstates"});
            this.connection.send(notify);
        }
        return true;
    }

    if(this.friends[chat_buddy] != null) {
        this.friends[chat_buddy].activity=status ;
    }

    if(this.chats[chat_buddy] != null ) {
        this.chats[chat_buddy].chat_status  = status ;
    }
    this.trigger('chatStatus',[chat_buddy,status]);
    this.__log(chat_buddy + ' buddy is "'+status+'"');
}

function yajschat_getMessage(msg) {
     //in this function 'this' is a Strophe obj !
    yajschat_obj = YAJSChat;


    var from    = $(msg).attr('from');
    var from_id = Strophe.getBareJidFromJid(from) ; 
    var to_id   = Strophe.getBareJidFromJid(yajschat_obj.connection.jid) ;

    var is_composing = $(msg).children('composing');
    if ( is_composing.length > 0 ) { yajschat_obj.__setChatStatus(from_id,'composing',true) ;  return true ; }
    
    var is_paused    = $(msg).children('paused'); 
    if ( is_paused.length > 0 ) { yajschat_obj.__setChatStatus(from_id,'paused',true); return true; } 

    var is_inactive    = $(msg).children('inactive');
    if ( is_inactive.length > 0 ) { yajschat_obj.__setChatStatus(from_id,'inactive',true);  return true; } 

    var is_gone    = $(msg).children('gone');
    if ( is_gone.length > 0 ) { yajschat_obj.__setChatStatus(from_id,'gone',true);  return true; } 



    var is_active    = $(msg).children('active');
    if ( is_active.length > 0 ) { yajschat_obj.__setChatStatus(from_id,'active',true); } 

    var body = $(msg).children('body').text();
    if(is_active.length>0 && body.length==0) return true ;

    yajschat_obj.__appendChat( from_id ,  to_id , body );
    if(body == '' )
        console.log(msg);
    
    yajschat_obj.trigger('getMessage',[yajschat_obj.__getChat(from_id)]);
    
    yajschat_obj.__log('You got new message: '+ body + ' from: '+from_id );
    return true;
}

function yajschat_sendMessage(to,body){
    
    if( to ) {
        from = this.connection.jid ;
        this.__log('send message from '+ from + ' to ' + to + ' with content : '+body);
        var reply = $msg({to: to, from: from, type: 'chat'}).c('body').t(body).up().c('active', {xmlns: "http://jabber.org/protocol/chatstates"});
        this.connection.send(reply.tree());
        var from_id = Strophe.getBareJidFromJid(this.connection.jid) ;
        this.__appendChat(from_id ,to,body);
        //we need to set last active by dirty code ! 
        if(this.chats[to] != null )  this.chats[to].last_status='active';
        yajschat_obj.trigger('sendMessage',[yajschat_obj.__getChat(to)]);
        return true ;
    }
    return false ;
}

function yajschat_disconnect() {
    this.connection.disconnect();
}

function yajschat_init(jid,password) {
    //do some staff to init YAJSChat
    this.jid=jid;
    this.password=password;
    this.bosh_service= 'http://localhost:5280/bosh';
    this.__connect();
}

function yajschat_connect(){
    this.connection = new Strophe.Connection(this.bosh_service);
    this.connection.connect(this.jid,this.password,this.__onConnect);
}

function yajschat_onConnect (status){
    //in this function 'this' is a Strophe obj !
    yajschat_obj = YAJSChat;
    if  ( status == Strophe.Status.ERROR ) {
        yajschat_obj.trigger('error');
        yajschat_obj.__log('Strophe is got error.');
    }
    else if  ( status == Strophe.Status.CONNECTING ) {
        yajschat_obj.trigger('connecting');
        yajschat_obj.__log('Strophe is connecting.');
    } else if ( status == Strophe.Status.CONNFAIL ) {
        yajschat_obj.trigger('connfail');
        yajschat_obj.__log('Strophe failed to connect.');
    } else if ( status == Strophe.Status.AUTHENTICATING ) {
        yajschat_obj.trigger('authenticating');
        yajschat_obj.__log('Strophe is authenticating ') ; 
    } else if ( status == Strophe.Status.AUTHFAIL ) {
        yajschat_obj.trigger('authfail');
        yajschat_obj.__log('Struophe is got authentication fail') ; 
    } else if ( status == Strophe.Status.CONNECTED ) {
        yajschat_obj.trigger('connected');
        yajschat_obj.__log('Strophe is connected.');
        yajschat_obj.__log('Connect with jid : ' + yajschat_obj.connection.jid);

        //get friends list
        var iq = $iq({type: 'get'}).c('query', {xmlns: 'jabber:iq:roster'});
        yajschat_obj.connection.sendIQ(iq, yajschat_obj.__getRoster);
        //update friends list
        yajschat_obj.connection.addHandler(yajschat_obj.__onrosterChanged,"jabber:iq:roster", "iq", "set");

        //check online users
        yajschat_obj.connection.addHandler(yajschat_obj.__onPresence, null, "presence");
        //ready for chat 
        yajschat_obj.connection.addHandler(yajschat_obj.__getMessage, null, "message", "chat");
        yajschat_obj.connection.send($pres());

    } else if ( status == Strophe.Status.DISCONNECTING ) {
        yajschat_obj.trigger('disconnecting');
        yajschat_obj.__log('Strophe is disconnecting.');
    } else if ( status == Strophe.Status.DISCONNECTED ) {
        yajschat_obj.trigger('disconnected');
        yajschat_obj.__log('Strophe is disconnected.');
    } else if ( status == Strophe.Status.ATTACHED ) {
        yajschat_obj.trigger('disconnected');
        yajschat_obj.__log('Strophe is attached.');

    }
}

function yajschat_log(text) {
    if ( $('#log').length>0 ) {
        $('#log').html( $('#log').html() + "<br />" + text );
    }else {
    console.log(text);
    }
}





